package org.ztr.yanai.blog.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.ztr.yanai.blog.constant.RedisKeyConstants;
import org.ztr.yanai.blog.exception.BusinessException;
import org.ztr.yanai.blog.exception.ErrorCode;
import org.ztr.yanai.blog.utils.IpUtil;

import java.util.concurrent.TimeUnit;

/**
 * @Author: ZhaoTR
 * @Date: Created in 2025/11/22 14:30
 * @Description: 限流拦截器，基于Redis实现接口限流
 * @Version: 1.0
 */
@Slf4j
@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    @Autowired(required = false)
    private StringRedisTemplate redisTemplate;

    /**
     * 时间窗口（秒）
     */
    private static final long TIME_WINDOW = 60;

    /**
     * 最大请求次数
     */
    private static final long MAX_REQUESTS = 100;

    @Override
    public boolean preHandle(
            @NotNull HttpServletRequest request,
            @NotNull HttpServletResponse response,
            @NotNull Object handler
    ) {
        // 如果Redis未配置，跳过限流
        if (redisTemplate == null) {
            return true;
        }

        String ip = IpUtil.getClientIp(request);
        String key = RedisKeyConstants.RateLimit.ipKey(ip);

        try {
            // 获取当前请求次数
            String countStr = redisTemplate.opsForValue().get(key);
            long count = countStr == null ? 0 : Long.parseLong(countStr);

            if (count >= MAX_REQUESTS) {
                log.warn("IP {} 请求频率过高，已被限流", ip);
                throw new BusinessException(ErrorCode.OPERATION_FAILED, "请求过于频繁，请稍后再试");
            }

            // 增加计数
            redisTemplate.opsForValue().increment(key);

            // 如果是第一次请求，设置过期时间
            if (count == 0) {
                redisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);
            }

            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("限流检查异常: {}", e.getMessage());
            // 出现异常时放行请求
            return true;
        }
    }
}
